package com.gcd.inference;

import android.text.style.ParagraphStyle;
import android.util.Log;

import com.gcd.Global;
import com.gcd.Pair;
import com.gcd.knowledge.Node;
import com.gcd.knowledge.PARAMETERS;
import com.gcd.knowledge.Tree;

public class Machine {

	Node currentNode;
	Tree tree;
	Pair facts = Global.facts;;
	Pair iR = Global.intermediateResult; // Intermediate Result
	Integer solusiAnak;
	Integer solusiJandu;
	Integer solusiOrtu;
	Integer solusiSaudara;
	Integer solusiCucu;

	float harta = 0;
	float totalHartaTerima = 0;
	float bagianAnakLaki = 0;
	float bagianAnakPerempuan = 0;
	float bagianIstri = 0;
	float bagianSuami = 0;
	float bagianBapak = 0;
	float bagianIbu = 0;
	float bagianSaudaraLaki = 0;
	float bagianSaudaraPerempuan = 0;
	float bagianCucuLaki = 0;
	float bagianCucuPerempuan = 0;
	int number = 0;

	public void doInferencePartial(int i) throws Exception {
		tree = Global.tree[i];
		currentNode = tree.getNode(0);
		String key = "explanation tree " + i;
		int answer;
		Log.d("sout", "hai");
		iR.put(key, "");

		while (currentNode != null && currentNode.type != Node.TYPE.SOLUTION) {
			Log.d("sout", "node : " + currentNode);
			iR.put(key, iR.get(key) + currentNode.explanation + " ");
			answer = Integer.parseInt(facts.get(currentNode.question));
			Log.d("sout", "answer : " + answer);
			currentNode = tree.find(currentNode.answers[answer]);
		}

		if (currentNode == null) {
			throw new Exception("Current node is null");
		}

		System.out.println(currentNode.solution);
		iR.put(key, iR.get(key) + currentNode.explanation);
		Log.d("sout", "explanation : " + iR.get(key));
		iR.put("solution tree " + i, currentNode.solution);
	}

	public void doInference() throws Exception {
		for (int i = 0; i < Global.tree.length; ++i) {
			doInferencePartial(i);
		}
		construct();

		Log.d("sout", "laki-laki : " + bagianAnakLaki);
		Log.d("sout", "perempuan : " + bagianAnakPerempuan);
		Log.d("sout", "istri     : " + bagianIstri);
		Log.d("sout", "suami     : " + bagianSuami);
		Log.d("sout", "ayah      : " + bagianBapak);
		Log.d("sout", "ibu       : " + bagianIbu);
		Log.d("sout", "saudara laki2 : " + bagianSaudaraLaki);
		Log.d("sout", "saudara perempuan : " + bagianSaudaraPerempuan);
		Log.d("sout", "cucu laki2 : " + bagianCucuLaki);
		Log.d("sout", "cucu perempuan : " + bagianCucuPerempuan);
	}

	public void construct() {
		harta = Integer.parseInt(facts.get("harta"));
		solusiAnak = Integer.parseInt(iR.get("solution tree 0"));
		solusiJandu = Integer.parseInt(iR.get("solution tree 1"));
		solusiOrtu = Integer.parseInt(iR.get("solution tree 2"));
		solusiSaudara = Integer.parseInt(iR.get("solution tree 3"));
		solusiCucu = Integer.parseInt(iR.get("solution tree 4"));

		calculateAll();
		
		// Add to Intermediate result
		addSolutionToIR();
		
		isAumOrAul();
	}

	private void calculateAll() {
		calculateJandu();
		calculateOrtu();
		calculateSaudara();
		calculateAnak();
		calculateCucu();
	}

	private void addSolutionToIR() {
		iR.put("bagianAnakLaki", bagianAnakLaki);
		iR.put("bagianAnakPerempuan", bagianAnakPerempuan);
		iR.put("bagianIstri", bagianIstri);
		iR.put("bagianSuami", bagianSuami);
		iR.put("bagianBapak", bagianBapak);
		iR.put("bagianIbu", bagianIbu);
		iR.put("bagianSaudaraLaki", bagianSaudaraLaki);
		iR.put("bagianSaudaraPerempuan", bagianSaudaraPerempuan);
		iR.put("bagianCucuLaki", bagianCucuLaki);
		iR.put("bagianCucuPerempuan", bagianCucuPerempuan);
	}

	private void isAumOrAul() {
		totalHartaTerima = bagianAnakLaki + bagianAnakPerempuan + bagianIstri
				+ bagianSuami + bagianBapak + bagianIbu + bagianSaudaraLaki
				+ bagianSaudaraPerempuan + bagianCucuLaki + bagianCucuPerempuan;
		  
		if (Math.abs(totalHartaTerima - harta) > 2) { // total != harta
			// Is Aum
			if (totalHartaTerima < harta) {
				explainAum();
			}

			// Is Aul
			if (totalHartaTerima > harta) {
				explainAul();
			}
		}
	}

	private void explainAul() {
		StringBuilder sb = new StringBuilder();
		
		sb.append("Total harta yang diperoleh oleh semua ahli waris adalah ")
		.append(totalHartaTerima)
		.append(" sedangkan harta hanya waris pewaris adalah ")
		.append(harta).append(". Ini berarti harta yang dibagi lebih besar dari harta sebenarnya.")
		.append("Oleh karena itu setiap harta yang diterima oleh ahli waris dikalikan dengan ")
		.append(harta).append(" / ").append(totalHartaTerima).append(".");
		
		iR.put("aul", sb.toString());
	}

	private void explainAum() {
		StringBuilder sb = new StringBuilder();
		float sisa = harta - totalHartaTerima;
		
		sb.append("Total harta yang diperoleh oleh semua ahli waris adalah ").append(totalHartaTerima)
		.append(" sedangkan harta waris pewaris adalah ").append(harta).append(". Ini berarti sebanyak ")
		.append(sisa).append(" harta tersisa. Sisa harta ini dibagi rata ke semua ahli waris yang menerima.");
		
		iR.put("aum", sb.toString());
	}
	
	private int numAhliWaris() {
		int num = 0;
		
		if (bagianAnakLaki != 0)		++num;
		if (bagianAnakPerempuan != 0)	++num;
		if (bagianBapak != 0)			++num;
		if (bagianCucuLaki != 0)		++num;
		if (bagianCucuPerempuan != 0)	++num;
		if (bagianIbu != 0)				++num;
		if (bagianIstri != 0)			++num;
		if (bagianSaudaraLaki != 0)		++num;
		if (bagianSaudaraPerempuan != 0)++num;
		if (bagianSuami != 0)			++num;
		
		return num;
	}

	private void calculateCucu() {
		switch (solusiCucu) {
		case 2: {
			bagianCucuLaki = harta;
			break;
		}

		case 3: {
			bagianCucuPerempuan = PARAMETERS.PEREMPUAN_SATU * harta;
			break;
		}

		case 4: {
			bagianCucuLaki = harta;
			break;
		}

		case 5: {
			bagianCucuPerempuan = PARAMETERS.PEREMPUAN_N * harta;
			break;
		}

		case 6: {
			float pembagi = PARAMETERS.PEREMPUAN + PARAMETERS.LAKI_LAKI;
			bagianCucuPerempuan = PARAMETERS.PEREMPUAN / pembagi * harta;
			bagianCucuLaki = PARAMETERS.LAKI_LAKI / pembagi * harta;
			break;
		}
		}
	}

	private void calculateSaudara() {
		switch (solusiSaudara) {
		case 2: {
			bagianSaudaraLaki = harta
					- (bagianIstri + bagianSuami + bagianIbu + bagianBapak);
			break;
		}

		case 3: {
			bagianSaudaraPerempuan = PARAMETERS.PEREMPUAN_SATU * harta;
			break;
		}

		case 4: {
			bagianSaudaraLaki = harta
					- (bagianSuami + bagianIstri + bagianIbu + bagianBapak);
			break;
		}

		case 5: {
			bagianSaudaraPerempuan = PARAMETERS.PEREMPUAN_N * harta;
			break;
		}

		case 6: {
			float pembagi = PARAMETERS.PEREMPUAN + PARAMETERS.LAKI_LAKI;
			bagianSaudaraPerempuan = PARAMETERS.PEREMPUAN / pembagi * harta;
			bagianSaudaraLaki = PARAMETERS.LAKI_LAKI / pembagi * harta;
			break;
		}
		}
	}

	private void calculateOrtu() {
		switch (solusiOrtu) {
		case 3: {
			bagianBapak = PARAMETERS.AYAH_HAS_IBU_HAS * harta;
			bagianIbu = PARAMETERS.AYAH_HAS_IBU_HAS * harta;
			iR.put("bagianOrtu", "1 orang bapak memperoleh " + PARAMETERS.AYAH_HAS_IBU_HAS + " * harta = " + bagianBapak + "\n" 
					+ "1 orang ibu memperoleh " + PARAMETERS.AYAH_HAS_IBU_HAS + " * harta = " + bagianIbu);
			break;
		}

		case 4: {
			bagianBapak = PARAMETERS.AYAH_HAS_IBU_HASNOT * harta;
			iR.put("bagianOrtu", "1 orang bapak memperoleh " + PARAMETERS.AYAH_HAS_IBU_HASNOT + " * harta = " + bagianBapak);
			break;
		}

		case 6: {
			bagianIbu = PARAMETERS.AYAH_HASNOT_IBU_HAS * harta;
			iR.put("bagianOrtu", "1 orang ibu memperoleh " + PARAMETERS.AYAH_HASNOT_IBU_HAS + " * harta = " + bagianIbu);
			break;
		}

		case 10: {
			bagianIbu = PARAMETERS.AYAH_HAS_IBU_HAS_SAUDARA_HAS * harta;
			bagianBapak = harta
					- ((bagianSuami + bagianIstri) + bagianSaudaraLaki + bagianSaudaraPerempuan);
			break;
		}

		case 11: {
			bagianBapak = harta
					- ((bagianSuami + bagianIstri) + bagianSaudaraLaki + bagianSaudaraPerempuan);
			break;
		}
		case 13: {
			bagianIbu = PARAMETERS.AYAH_HASNOT_IBU_HAS_SAUDARA_HAS * harta;
			break;
		}
		case 16: {
			bagianIbu = PARAMETERS.AYAH_HAS_IBU_HAS_SAUDARA_HASNOT * harta;
			bagianBapak = harta
					- ((bagianSuami + bagianIstri) + bagianSaudaraLaki + bagianSaudaraPerempuan);
			break;
		}
		case 17: {
			bagianBapak = harta
					- ((bagianSuami + bagianIstri) + bagianSaudaraLaki + bagianSaudaraPerempuan);
			break;
		}
		case 19: {
			bagianIbu = PARAMETERS.AYAH_HASNOT_IBU_HAS_SAUDARA_HASNOT * harta;
			break;
		}
		}
	}

	private void calculateJandu() {
		switch (solusiJandu) {
		case 4:
			bagianIstri = PARAMETERS.ISTRI_HAS_ANAK_YA * harta;
			break;
		case 5:
			bagianIstri = PARAMETERS.ISTRI_HAS_ANAK_TIDAK * harta;
			break;
		case 7:
			bagianSuami = PARAMETERS.SUAMI_HAS_ANAK_YA * harta;
			break;
		case 8:
			bagianSuami = PARAMETERS.SUAMI_HAS_ANAK_TIDAK * harta;
			break;

		}
	}

	private void calculateAnak() {
		int anakLaki = Integer.parseInt(facts.get("jumlah anak laki"));
		int anakPerempuan = Integer.parseInt(facts.get("jumlah anak perempuan"));
		
		switch (solusiAnak) {
		case 2:
			bagianAnakLaki = harta
					- (bagianSuami + bagianIstri + bagianIbu + bagianBapak);
			iR.put("bagianAnak", anakLaki + " orang anak laki-laki memperoleh : harta - (bagian orang tua + bagian suami/istri) = " + bagianAnakLaki);
			break;
		case 3:
			bagianAnakPerempuan = PARAMETERS.PEREMPUAN_SATU * harta;
			iR.put("bagianAnak", anakPerempuan + " orang anak perempuan memperoleh : " + PARAMETERS.PEREMPUAN_SATU + " * harta = " +  + bagianAnakPerempuan);
			break;
		case 4:
			bagianAnakLaki = harta
					- (bagianSuami + bagianIstri + bagianIbu + bagianBapak);
			iR.put("bagianAnak", anakLaki + " orang anak laki-laki, masing-masing memperoleh : (harta - (bagian orang tua + bagian suami/istri)) / " + anakLaki + " = " + (bagianAnakLaki / anakLaki));
			break;
		case 5:
			bagianAnakPerempuan = PARAMETERS.PEREMPUAN_N * harta;
			iR.put("bagianAnak", anakPerempuan + " orang anak perempuan, masing-masing memperoleh : (" + PARAMETERS.PEREMPUAN_N + " * harta) / " + anakPerempuan + " = "  + (bagianAnakPerempuan/ anakPerempuan));
			break;
		case 6:
			float pembagi = PARAMETERS.PEREMPUAN + PARAMETERS.LAKI_LAKI;
			bagianAnakPerempuan = PARAMETERS.LAKI_LAKI / pembagi * (harta - (bagianSuami + bagianIstri + bagianIbu + bagianBapak));;
			bagianAnakLaki = PARAMETERS.PEREMPUAN / pembagi * (harta - (bagianSuami + bagianIstri + bagianIbu + bagianBapak));;
			iR.put("bagianAnak", anakLaki + " orang anak laki-laki, masing-masing memperoleh : " + (bagianAnakLaki / anakLaki) + "\n"
					+ anakPerempuan + " orang anak perempuan, masing-masing memperoleh : " + bagianAnakPerempuan/ anakPerempuan + "\n"
					+ PARAMETERS.LAKI_LAKI + " * laki-laki = " + PARAMETERS.PEREMPUAN + " * perempuan");
			break;
		}
	}
}
